As will be familiar to those skilled in the art of programming, a program often comprises function calls which provide a return value(s) for subsequent use in the program. A synchronous program will typically wait for a function to return any values before continuing with its processing. Certain environments however cannot afford such waiting—they require almost instantaneous results. In for example a gaming environment, users are typically not prepared to wait 5 seconds whilst a screen updates. Good performance is required and yet games applications typically use a non-threaded model of programming thus preventing the use of parallel processing to achieve required performance levels. (This is because threads are typically under the control of the operating system and so do not therefore permit tight enough control by the games application programmer.)
To help achieve acceptable performance levels, asynchronous APIs and handles are often used. A handle is an abstract reference (label) which is associated with a function's return value and which can then be used to access that return value.
For example, a user program (application) may call function y on some API which may need to return value r. The time taken to process the request and actually return the value r may however be too long, and will have too large an impact on the user program. Instead, when the function is called, it returns a handle “handle_r”, which is an abstract reference to the actual return value, r, which will initially be unavailable. The work of actually processing the request made as a result of that function, and thus retrieving r, will not be immediately carried out. Instead, the user program will later provide the API with x milliseconds in which to actually do that work, and to obtain the return value r. Once the API's allotted time slot has expired, the user program will then query handle_r to determine whether it resolves to the return value r. If the answer is no, then the user application may do some additional processing, such as redrawing a screen, before requesting that the API re-attempt to obtain r and also before handle_r is queried again. The user application can periodically query the handle (interspersing this with additional processing) until handle_r finally resolves to the result r. Note, when r is finally returned from function y, it is stored in a block of memory and an entry in a lookup table is then resolved such that “handle_r” references the block of memory containing r. This time, when the user program queries handle_r, it is presented with access to r. Because the user application only provides the API with a short period of time in which to retrieve the object, the delay whilst this is happening is not discernible to a user.
In reality (given a good network connection) the return of a single value (simple object) should be achieved within the x milliseconds allowed for. Sometimes however API calls return more complex data structures. For example, a call may return a linked list of items, or a tree of items. Complex data structures are composed of many individual objects. These objects are then linked to each other via the use of object pointers, and the complex data structure is created as a result of this linkage.
When using asynchronous APIs, a function is not able to immediately return a result. Rather, a handle is returned instead. This handle is associated with an eventual return value (i.e. complex structure) generated by the asynchronous API (this value being the result of the initial function call). The user is informed of the return of this result and the association with the handle via a change in the handle's “state” (e.g. it moves from an “Empty” to a “Complete” state). The user then uses the handle to access the return value. As far as the user is concerned, the handle is not resolvable (i.e. is in the “Empty” state) until the structure is complete. The program need however not be blocked since as before it may provide the API with x milliseconds to retrieve n objects. During that time, the API may retrieve only 2 of those objects. These will be associated with a handle but to the user this handle does not yet resolve to a structure because all objects in the structure have not yet been retrieved. The program will continue its processing, will periodically request that the API retrieves more objects and will query the handle to determine whether it is resolvable. This can however take time (especially where network connections are involved and when large structures need to be retrieved) and this can be undesirable.